package com.glodon.paas.account.biz.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Repository;

import com.glodon.paas.account.api.bean.AccountConstant;
import com.glodon.paas.account.biz.UserBiz;
import com.glodon.paas.account.dao.AddressDao;
import com.glodon.paas.account.dao.AvatarDao;
import com.glodon.paas.account.dao.CompanyDao;
import com.glodon.paas.account.dao.ConsumerDao;
import com.glodon.paas.account.dao.ContactDao;
import com.glodon.paas.account.dao.ScopeDao;
import com.glodon.paas.account.dao.TokenDao;
import com.glodon.paas.account.dao.UserDao;
import com.glodon.paas.account.dao.domain.AddressEntity;
import com.glodon.paas.account.dao.domain.AvatarEntity;
import com.glodon.paas.account.dao.domain.CompanyEntity;
import com.glodon.paas.account.dao.domain.ConsumerEntity;
import com.glodon.paas.account.dao.domain.ContactEntity;
import com.glodon.paas.account.dao.domain.OAuthTokenEntity;
import com.glodon.paas.account.dao.domain.ScopeEntity;
import com.glodon.paas.account.dao.domain.UserEntity;
import com.glodon.paas.account.dao.redis.RedisTokenStore;
import com.glodon.paas.account.service.util.AccountPasswordEncoder;
import com.glodon.paas.account.service.util.AccountUtil;
import com.glodon.paas.exception.PaasServerExceptionFactory;
import com.glodon.paas.exception.i18n.ErrorCode;
import com.glodon.paas.util.UUIDUtil;

@Repository("userBiz")
public class UserBizImpl implements UserBiz {
	private static Logger logger = LoggerFactory.getLogger(UserBizImpl.class);

	
	@Autowired
	private UserDao userDao;
	
	@Autowired
	private TokenDao tokenDao;
	
	@Autowired
	private AddressDao addressDao;
	
	@Autowired
	private ContactDao contactDao;
	
	@Autowired
	private CompanyDao companyDao;
	
	@Autowired
	private ConsumerDao consumerDao;
	
	@Autowired
	private AvatarDao avatarDao;
	
	@Autowired
	private RedisTokenStore oauth2TokenDao;
	
	@Autowired
	private ScopeDao scopeDao;

	/**
	 * 用户注册，产生新用户
	 * 
	 * @param accountName
	 * @param accountType
	 * @param password
	 * @param passwordConfirm
	 * @return
	 */
	public UserEntity registerAccount(String accountName,Integer accountType, String password, Integer status){
		if (StringUtils.isEmpty(accountName) || StringUtils.isEmpty(password)) {
			throw PaasServerExceptionFactory.validateException("email or password is empty.", null);
		} 
		
		Integer judgedAccountType = AccountUtil.judgeAccountName(accountName, true);
		if(accountType == null){
			accountType = judgedAccountType;
		}else if(!accountType.equals(judgedAccountType)){
			throw PaasServerExceptionFactory.validateException("accountName not match accountType", null).setErrorCode(ErrorCode.ACCOUNT_NAME_BAD);
		}	
		if(getUserByAccountName(accountName,accountType, AccountConstant.USER_STATUS_ACTIVE) != null){
			throw PaasServerExceptionFactory.existException("User["+accountName+"] has been registed, can not registe it again.", null).setErrorCode(ErrorCode.EMAIL_REGISTED);
		}
		
		UserEntity user = new UserEntity();
		
		
		if(AccountConstant.ACCOUNT_NAME_EMAIL.equals(accountType)){
			user.setEmail(accountName);
			user.setMainAccountType(AccountConstant.ACCOUNT_NAME_EMAIL);
		}else if(AccountConstant.ACCOUNT_NAME_MOBILE.equals(accountType)){
			user.setMobile(accountName);
			user.setMainAccountType(AccountConstant.ACCOUNT_NAME_MOBILE);
		}else if(AccountConstant.ACCOUNT_NAME_NOMAL.equals(accountType)){
			user.setLoginname(accountName);
			user.setMainAccountType(AccountConstant.ACCOUNT_NAME_NOMAL);
		}
		user.setStatus(status);
		user.setPassword(password);
		AccountPasswordEncoder.encodePassword(user);
		this.insertUser(user);
		
		logger.debug("create User [accountName:"+accountName+"] success.");		
		return user;
	}
	

	@Override
	public void activeUser(String userId, String accountName, Integer accountType, String password) {
		if(accountType == null){
			accountType = AccountUtil.judgeAccountName(accountName, true);			
		}
		
		UserEntity user = null;
		// userId查询
		if(StringUtils.isNotBlank(userId)){
			user = getUser(userId);
			if(user == null){
				throw PaasServerExceptionFactory.notFoundException("user not fount userId="+userId, null).setErrorCode(ErrorCode.USER_NOT_EXIST);
			}
		}
		
		//accountName查询
		if(user == null){
			// 是否有激活的account
			user = getUserByAccountName(accountName, accountType, AccountConstant.USER_STATUS_ACTIVE);
			if(user != null){
				throw PaasServerExceptionFactory.existException("User["+accountName+"] has been registed, can not registe it again.", null).setErrorCode(ErrorCode.EMAIL_REGISTED);
			}else{
				user = getUserByAccountName(accountName, accountType, AccountConstant.USER_STATUS_INACTIVE);
			}
		}

		if(AccountConstant.ACCOUNT_NAME_EMAIL.equals(accountType)){
			user.setEmail(accountName);
			user.setMainAccountType(AccountConstant.ACCOUNT_NAME_EMAIL);
		}else if(AccountConstant.ACCOUNT_NAME_MOBILE.equals(accountType)){
			user.setMobile(accountName);
			user.setMainAccountType(AccountConstant.ACCOUNT_NAME_MOBILE);
		}else if(AccountConstant.ACCOUNT_NAME_NOMAL.equals(accountType)){
			user.setLoginname(accountName);
			user.setMainAccountType(AccountConstant.ACCOUNT_NAME_NOMAL);
		}
		
		user.setStatus(AccountConstant.USER_STATUS_ACTIVE);
		user.setUpdatedTime(new Date());
		if(StringUtils.isNotBlank(password)){
			user.setPassword(password);
			AccountPasswordEncoder.encodePassword(user);
		}
		try {
			userDao.update(user);	
		} catch (Exception e) {
			logger.error(e.getMessage(),e);
			throw PaasServerExceptionFactory.validateException("active User error", e).setErrorCode(ErrorCode.ACCOUNT_ERROR);
		}			
	}
	
	public String insertUser(UserEntity user) {
		if(StringUtils.isEmpty(user.getId())){
			user.setId(UUIDUtil.getUUIDStr());
		}
		user.setCreatedTime(new Date());
		user.setUpdatedTime(user.getCreatedTime());
		return userDao.insert(user);
	}

	@Override
	public UserEntity getUser(String userId) {
		if (StringUtils.isEmpty(userId)) {
			throw PaasServerExceptionFactory.validateException("userId is empty.", null);
		}
		return userDao.get(userId);
	}

	@Override
	public void updateUser(UserEntity user) {
		if (user == null) {
			throw PaasServerExceptionFactory.validateException("user is empty.", null);
		}
		user.setUpdatedTime(new Date());
		userDao.update(user);
	}

	@Override
	public void resetPassword(String userId, String newPassword, String authorization, Integer authorizationType) {
		if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(newPassword)) {
			throw PaasServerExceptionFactory.validateException("userId or password is empty.", null);
		}
		UserEntity userdb = userDao.get(userId);		
		if(userdb == null){
			throw PaasServerExceptionFactory.notFoundException("user not found.", null);			
		}
		boolean haveRight = false;
		//校验
		if(AccountConstant.AUTHORIZATION_TYPE_SYS.equals(authorizationType)){
			haveRight = true;
		}
		
		//根据密码验证
		if(!haveRight && AccountConstant.AUTHORIZATION_TYPE_PWD.equals(authorizationType)){			 
			haveRight = AccountPasswordEncoder.isPasswordValid(userdb.getPassword(), authorization, userdb.getPasswordSalt());
			if(!haveRight){
				throw PaasServerExceptionFactory.validateException("old password is incorrect.", null).setErrorCode(ErrorCode.PASSWORD_ERROR);	
			}
		}
		if(!haveRight){
			throw PaasServerExceptionFactory.accessForbidden("resetPassword", null);	
		}
		
		userdb.setPassword(newPassword);
		AccountPasswordEncoder.encodePassword(userdb);
		userDao.update(userdb);
	}

	@Override
	public UserEntity getUserByAccountName(String accountName, Integer accountType, Integer status) {
		if(accountType == null){
			accountType = AccountUtil.judgeAccountName(accountName,true);
		}
		if(accountType.equals(AccountConstant.ACCOUNT_NAME_EMAIL)){
			return userDao.getByAccountName(null,accountName,null,status);
		}
		
		if(accountType.equals(AccountConstant.ACCOUNT_NAME_MOBILE)){
			return userDao.getByAccountName(null,null,accountName,status);
		}
		return null;
	}

	@Override
	public void deleteToken(String tokenId) {
		if (StringUtils.isEmpty(tokenId)) {
			throw PaasServerExceptionFactory.validateException("tokenId is empty.", null);
		}
//		OAuthTokenEntity token = tokenDao.get(tokenId);
//		oAuthAuthorizationDao.delete(token.getoAuthAuthorizationId());
		tokenDao.delete(tokenId);
		
		oauth2TokenDao.removeAccessToken(tokenId);
	}

	@Override
	public List<OAuthTokenEntity> getAccessTokens(String userId) {
		if (StringUtils.isEmpty(userId)) {
			throw PaasServerExceptionFactory.validateException("userId is empty.", null);
		}
//		List<OAuthAuthorizationEntity> authorizations =oAuthAuthorizationDao.getAuthorizationsByUser(userId);
		List<OAuthTokenEntity> ret = tokenDao.getAccessTokens(userId);
//		if(authorizations!=null){
//			ret = new ArrayList<OAuthTokenEntity>();
//			for(OAuthAuthorizationEntity auth: authorizations){
//				ret.addAll(tokenDao.getAccessTokens(auth.getId()));
//			}
//		}
		return ret;
	}

	@Override
	public List<OAuth2AccessToken> getOAuth2Tokens(String userId) {
		if (StringUtils.isEmpty(userId)) {
			throw PaasServerExceptionFactory.validateException("userId is empty.", null);
		}

		List<OAuth2AccessToken> ret = new ArrayList<OAuth2AccessToken>();
		Collection<OAuth2AccessToken> tokens = oauth2TokenDao.findTokensByUserName(userId);
		for(OAuth2AccessToken token : tokens ){
			ret.add(token);
		}		

		return ret;
	}
	
	@Override
	public String getConsumerId(OAuth2AccessToken token){
		if(null == token){
			throw PaasServerExceptionFactory.validateException("token is invalid", null);
		}	
		
		return oauth2TokenDao.readAuthentication(token).getAuthorizationRequest().getClientId();
	}
	
	@Override
	public AddressEntity getAddress(String addressId) {
		if (StringUtils.isEmpty(addressId)) {
			throw PaasServerExceptionFactory.validateException("addressId is empty.", null);
		}
		return addressDao.get(addressId);
	}

	@Override
	public String insertAddress(AddressEntity addr) {
		if(addr == null){
			throw PaasServerExceptionFactory.validateException("Address is empty.", null);
		}
		if(StringUtils.isEmpty(addr.getId())){
			addr.setId(UUIDUtil.getUUIDStr());
		}
		return addressDao.insert(addr);
	}

	@Override
	public void updateAddress(AddressEntity addr) {
		if (addr == null) {
			throw PaasServerExceptionFactory.validateException("Address is empty.", null);
		}
		addressDao.update(addr);
	}

	@Override
	public ContactEntity getContact(String contactId) {
		if (StringUtils.isEmpty(contactId)) {
			throw PaasServerExceptionFactory.validateException("contactId is empty.", null);
		}
		return contactDao.get(contactId);
	}

	@Override
	public String insertContact(ContactEntity contact) {
		if(contact == null){
			throw PaasServerExceptionFactory.validateException("Address is empty.", null);
		}
		if(StringUtils.isEmpty(contact.getId())){
			contact.setId(UUIDUtil.getUUIDStr());
		}
		return contactDao.insert(contact);
	}

	@Override
	public void updateContact(ContactEntity contact) {
		if (contact == null) {
			throw PaasServerExceptionFactory.validateException("contact is empty.", null);
		}
		contactDao.update(contact);
	}

	@Override
	public CompanyEntity getCompany(String companyId) {
		if (StringUtils.isEmpty(companyId)) {
			throw PaasServerExceptionFactory.validateException("companyId is empty.", null);
		}
		return companyDao.get(companyId);
	}

	@Override
	public String insertCompany(CompanyEntity company) {
		if(company == null){
			throw PaasServerExceptionFactory.validateException("company is empty.", null);
		}
		if(StringUtils.isEmpty(company.getId())){
			company.setId(UUIDUtil.getUUIDStr());
		}
		return companyDao.insert(company);
	}

	@Override
	public void updateCompany(CompanyEntity company) {
		if (company == null) {
			throw PaasServerExceptionFactory.validateException("company is empty.", null);
		}
		companyDao.update(company);
	}

	@Override
	public ConsumerEntity getConsumerByKey(String key) {
		if (StringUtils.isEmpty(key)) {
			throw PaasServerExceptionFactory.validateException("consumer key is empty.", null);
		}
		return consumerDao.getConsumerByKey(key);
	}

	@Override
	public boolean checkEmailExist(String email) {
		UserEntity u = userDao.getByAccountName(null, email, null, AccountConstant.USER_STATUS_ACTIVE);
		return u!= null;
	}

	// 头像
	@Override
	public int saveAvatar(String id, String userId, Integer size, byte[] item){
		if(id == null){
			id = userId + "_"+ size;
		}
		AvatarEntity entity = avatarDao.get(id);
		if(entity == null){
			entity = new AvatarEntity();
			entity.setId(id);
			entity.setCreateTime(new Date());
		}
		
		entity.setItem(item);
		entity.setUpdateTime(new Date());
		avatarDao.delete(id);
		avatarDao.insert(entity);
		return 1;
	} 
	/**
	 * 
	 */
	@Override
	public AvatarEntity getAvatar(String id, String userId, Integer size){
		if(id == null){
			id = userId + "_"+ size;
		}
		return avatarDao.get(id);
	}
	@Override
	public int deleteAvatar(String id, String userId, Integer size){
		if(id == null){
			id = userId + "_"+ size;
		}
		return avatarDao.delete(id);
	}

	@Override
	public boolean checkAuthorization(String account, Integer accountType, String authorization, Integer authorizationType){
		//获取用户信息
		UserEntity user = null;
		if(AccountConstant.ACCOUNT_NAME_ID.equals(accountType)){
			user = this.getUser(account);
		}
		
		if(user == null){
			throw PaasServerExceptionFactory.notFoundException("can not find the user[account:"+account+"].", null).setErrorCode(ErrorCode.USER_NOT_EXIST);
		}
		
		//判断权限
		if(AccountConstant.AUTHORIZATION_TYPE_PWD.equals(authorizationType)){		
			 return AccountPasswordEncoder.isPasswordValid(user.getPassword(), authorization, user.getPasswordSalt());
		}
		
		throw PaasServerExceptionFactory.nosupport("authorizationType="+authorizationType);
		
	}


	/* (non-Javadoc)
	 * @see com.glodon.paas.account.biz.UserBiz#getUserByIds(java.lang.String[])
	 */
	@Override
	public List<UserEntity> getUserByIds(String[] userIds) {
		if(userIds == null || userIds.length==0){
			return new ArrayList<UserEntity>();
		}
		return userDao.getByIds(userIds);
	}
	public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }


    @Override
    public void addProjectRole(String id,String userId, String projectId, String roleId,String orgId) {
        userDao.addProjectRole(id,userId, projectId, roleId,orgId);
    }


	@Override
	public int deleteProjectRole(String userId, String projectId, String roleId,String orgId) {
		return userDao.deleteProjectRole(userId, projectId, roleId,orgId);
		
	}


	@Override
	public int updateProjectRole(String projectId, String oldeRoleId,
			String newRoleId) {
		return userDao.updateProjectRole(projectId, oldeRoleId, newRoleId);
	}
	
	@Override
	public List<ScopeEntity> getScope(String scopes){
		List<ScopeEntity> entityList = new ArrayList<ScopeEntity>();
		String[] scopeList = StringUtils.split(scopes, ' ');
    	for(String s : scopeList){
    		entityList.add(scopeDao.get(s));  
    	}      	
		return entityList;
	}
}
